#pragma once

#include <vector>
#include <map>
#include <memory>

#include "net/libgo.h"
#include "libzqutil/log.h"
#include "libzqutil/ustring.h"
#include "libzqutil/random.h"

#include "net/msgpack.h"
#include "net/server_impl.h"
#include "net/client_impl.h"
#include "libzqutil/ini/SimpleIni.h"
#include "json11/json11.hpp"
#include "register.h"
#include "method_mgr.h"
namespace libzq
{
	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	class Server :
		public ServerImpl,
		public Mgr,
		public Reg
	{
		class ServerConn :
			public ClientImpl
		{
		public:
			ServerConn(shared_ptr<tcp::socket> sock, Server* server);
			void on_handle(std::shared_ptr<MsgPacker> msg) override;

		private:
			void write_response(const string& msgid, const Protocol& resp);
		private:
			Server* _server;
		};
	public:
		void connection_connected(std::shared_ptr<tcp::socket> sock) override;
		void on_boradcast(std::shared_ptr<MsgPacker> msg) override;
	};


	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	inline Server<Protocol, Handler, Mgr, Reg>::ServerConn::ServerConn(shared_ptr<tcp::socket> sock, Server * server) :
		ClientImpl(sock),
		_server(server)
	{

	}

	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	inline void Server<Protocol, Handler, Mgr, Reg>::ServerConn::on_handle(std::shared_ptr<MsgPacker> msg)
	{
		string&& msgid = msg->msgid();
		// 请求已经超时
		if (msg->is_expire())
		{
			LOGW("request %s expired", msgid);
			return;
		}
		string&& msg_ = msg->msg_body();
		string err;

		auto req = Protocol();
		req.parse(msg_, err);
		if (!err.empty())
		{
			LOGE("Parse req error [%s]", err);
			return;
		}
		string method = req.method();
		if (method.empty())
		{
			LOGE("Protocol error [method is missed]");
			return;
		}
		auto handler = _server->find_handler(method);
		if (handler != nullptr)
		{
			go_dispatch(egod_local_thread)[this, handler, req, method, msgid]()
			{
				auto ret = (*handler)(req);
				write_response(msgid, ret);
			};
		}
		else
		{
			Protocol ret = Protocol();
			string errmsg = format("Method [%s] is not found", method);
			ret.set_error(-999, errmsg.c_str());
			write_response(msgid, ret);
		}
	}

	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	inline void Server<Protocol, Handler, Mgr, Reg>::connection_connected(std::shared_ptr<tcp::socket> sock)
	{
		try
		{
			auto endpoint = sock->remote_endpoint();
			LOGT("New Client from [%s:%d] connected", endpoint.address().to_string(), endpoint.port());
		}
		catch (boost::system::error_code& ec)
		{
			LOGT("New Client connected");
		}
		std::shared_ptr<ServerConn> client = make_shared<ServerConn>(sock, this);
		_clients.push_back(client);
		client->set_disconnect_cb(std::bind(&Server::connection_disconnect, this, std::placeholders::_1));
		client->start_serve();
	}

	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	inline void Server<Protocol, Handler, Mgr, Reg>::on_boradcast(std::shared_ptr<MsgPacker> msg)
	{
		string&& msgid = msg->msgid();
		// 请求已经超时
		if (msg->is_expire())
		{
			LOGW("Request [ %s ] expired", msgid);
			return;
		}
		string&& msg_ = msg->msg_body();
		string err;

		auto req = Protocol();
		req.parse(msg_, err);
		if (!err.empty())
		{
			LOGT(msg_);
			LOGE("Parse req error [%s]", err);
			return;
		}
		string method = req.method();
		if (method.empty())
		{
			LOGE("Protocol error [method is missed]");
			return;
		}
		auto handler = this->find_handler(method);
		if (handler != nullptr)
		{
			go_dispatch(egod_local_thread)[handler, req]()
			{
				auto ret = (*handler)(req);
			};
		}
		else
		{
			LOGE("Boradcast method [ %s ] is not found", method);
		}
	}

	template<typename Protocol, typename Handler, typename Mgr, typename Reg>
	inline void Server<Protocol, Handler, Mgr, Reg>::ServerConn::write_response(const string& msgid, const Protocol & resp)
	{
		string resp_str = resp.dumps();
		MsgPacker msg(resp_str, msgid.c_str());
		write(msg);
	}

}